package com.woniu.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniu.common.BaseForm;
import com.woniu.constants.CommonConstants;
import com.woniu.constants.ErrorConstants;
import com.woniu.constants.RedisConstants;
import com.woniu.entity.*;
import com.woniu.exception.MyErrorException;
import com.woniu.form.OpenRedPacketForm;
import com.woniu.mapper.InviteFireworksRecordMapper;
import com.woniu.mapper.RedPacketPoolMapper;
import com.woniu.service.*;
import com.woniu.utils.*;
import com.woniu.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description:
 * @Author: woniu
 * @date: 2024/1/2 14:16
 */
@Service
public class RedPacketServiceImpl implements RedPacketService {

    @Autowired
    private InviteFireworksRecordMapper inviteFireworksRecordMapper;

    @Autowired
    private RedPacketPoolMapper redPacketPoolMapper;

    @Autowired
    private NuserService nuserService;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private YaoExceptionsService yaoExceptionsService;

    @Autowired
    private WechatService wechatService;

    @Autowired
    private TokenUtil tokenUtil;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private RestTemplateUtil restTemplateUtil;

    @Autowired
    private RedisUtil redisUtil;

    private static final ReentrantLock redPackLock = new ReentrantLock();

    /**
     * 抢红包
     * @return
     */
    @Override
    public SnatchRedPacketVO snatchRedPacket() {

        // 结果
        SnatchRedPacketVO result = new SnatchRedPacketVO();

        String userId = tokenUtil.getUserId();

        // 查询用户
        Nuser nuser = nuserService.getById(userId);
        if (nuser == null){
            throw new MyErrorException(ErrorConstants.USER_IS_NULL);
        }

        String nowStartDate = TimeUtil.getNowStartDate();
        String nowEndDate = TimeUtil.getNowEndDate();
        // 判断用户今日是否已经中过红包
        if (redPacketPoolMapper.existReceivedByNowDateAndUserId(nowStartDate,nowEndDate,userId)){
            throw new MyErrorException(ErrorConstants.RED_PACKET_USER_TODAY_IS_NOT_NULL);
        }

        // 查询是否有抢红包资格,1.21改为只查是否放过烟花
//        InviteFireworksRecord inviteFireworksRecord = inviteFireworksRecordMapper.selectOne(new LambdaQueryWrapper<InviteFireworksRecord>()
//                .eq(InviteFireworksRecord::getNuserId, userId)
//                .eq(InviteFireworksRecord::getInviteNewPeople, true)
//                .eq(InviteFireworksRecord::getSetOffFireworks, true)
//                .eq(InviteFireworksRecord::getRedPacketReceived, false)
//                .last(" limit 1"));

        InviteFireworksRecord inviteFireworksRecord = inviteFireworksRecordMapper.selectOne(new LambdaQueryWrapper<InviteFireworksRecord>()
                .eq(InviteFireworksRecord::getNuserId, userId)
                .eq(InviteFireworksRecord::getSetOffFireworks, true)
                .eq(InviteFireworksRecord::getRedPacketReceived, false)
                .last(" limit 1"));


        if (inviteFireworksRecord == null){
            throw new MyErrorException(ErrorConstants.SNATCH_RED_PACKET_CONDITION_NO);
        }

        // 更新红包机会已使用,只要调用了接口不管有没有抢中，就会减掉机会
        inviteFireworksRecordMapper.update(null,new LambdaUpdateWrapper<InviteFireworksRecord>()
                .eq(InviteFireworksRecord::getId,inviteFireworksRecord.getId())
                .set(InviteFireworksRecord::getRedPacketReceived,true)
                .set(InviteFireworksRecord::getUpdateTime,new Date()));

        // 查询每天是否已经中超过10个
        String redPacketCountKey = RedisConstants.REDPACKET_EVERDAY_COUNT;

        String redPacketCount = redisUtil.getString(redPacketCountKey);
        if (!StringUtils.isEmpty(redPacketCount) && Integer.parseInt(redPacketCount) >= 9){
            if (!randomFlag()){
                result.setSuccess(false);
                return result;
            }
        }else {
            // 总次数key存在，则自增1
            if (redisUtil.exists(redPacketCountKey)) {
                redisUtil.setIncrement(redPacketCountKey, (long) 1);
            } else {
                // 计算距离0点的结束时间
                Long timeLeft = TimeUtil.calculateTime();
                redisUtil.setString(redPacketCountKey, timeLeft);
            }
        }



        redPackLock.lock();

        RedPacketPool redPacket = null;
        // 先查询是否还有大红包
        redPacket = redPacketPoolMapper.findOneMaxByNowDate(nowStartDate, nowEndDate, 0.5);

        // 没有则判断当天是否还有红包
        if (redPacket == null){
            redPacket = redPacketPoolMapper.findOneByNowDate(nowStartDate, nowEndDate);
        }

        if (redPacket == null){
            redPackLock.unlock();
            result.setSuccess(false);
            return result;
        }
        boolean update = false;
        try {
            // 更新红包已被使用
            update = redPacketPoolMapper.update(null, new LambdaUpdateWrapper<RedPacketPool>()
                    .eq(RedPacketPool::getId, redPacket.getId())
                    .eq(RedPacketPool::getAlreadyReceived, false)
                    .set(RedPacketPool::getUpdateTime, new Date())
                    .set(RedPacketPool::getReceiveNuserId, userId)
                    .set(RedPacketPool::getAlreadyReceived, true)) > 0;
        }catch (Exception e){
            throw new MyErrorException("网络有延迟~");
        }finally {
            redPackLock.unlock();
        }


        if (update){
            result.setMoney(redPacket.getRedPacketMoney());
            result.setSuccess(true);
            // 把所有次数清空
            inviteFireworksRecordMapper.update(null, new LambdaUpdateWrapper<InviteFireworksRecord>()
                    .eq(InviteFireworksRecord::getNuserId, nuser.getId())
                    .eq(InviteFireworksRecord::getRedPacketReceived, false)
                    .set(InviteFireworksRecord::getRedPacketReceived, true)
                    .set(InviteFireworksRecord::getUpdateTime, new Date()));

//            result.setRedPacketId(redPacket.getId());
//            result.setExistUopenid(!StringUtils.isEmpty(nuser.getUOpenid()));
            // 这里异步调用微信商户转账到零钱功能
            wechatPayAsync(nuser.getOpenid(),redPacket.getRedPacketMoney(),redPacket.getId());

        }else {
            result.setSuccess(false);
        }

        return result;
    }


    private boolean randomFlag(){
        Integer[] arr = new Integer[]{1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2};

        Random random = new Random();

        if (arr[random.nextInt(arr.length)].equals(1)){
            return true;
        }
        return false;
    }

    /**
     * 转账
     * @param openid
     */
    @Async
    public void wechatPayAsync(String openid,Double moneyD,Integer redPacketId){
        // 商户批次号
        String outBatchNo = new SimpleDateFormat("yyyyMMddHHmm").format(new Date()) + IdUtil.getSnowflake(0, 0).nextIdStr();
        //处理金额
        Integer money = Integer.valueOf(String.valueOf(moneyD * 100).replace(".0", ""));
        // 更新红包转账订单号
        redPacketPoolMapper.update(null,new LambdaUpdateWrapper<RedPacketPool>()
                .eq(RedPacketPool::getId,redPacketId)
                .set(RedPacketPool::getWxOrderNumber,outBatchNo));
        // 转账
        wechatService.transferAccounts(outBatchNo,money,openid);
    }

    /**
     * 红包列表
     * @param form
     * @return
     */
    @Override
    public RedPacketVO redPacketList(BaseForm form) {
        String userId = tokenUtil.getUserId();
        RedPacketVO redPacketVO = new RedPacketVO();

        String nowStartDate = TimeUtil.getNowStartDate();
        String nowEndDate = TimeUtil.getNowEndDate();

        IPage<RedPacketPageVO> page = redPacketPoolMapper.findPageByNowDate(new Page<>(form.getPageCurrent()
                , form.getPageSize()), nowStartDate, nowEndDate);

        // 把昵称除了前一个字，其余全替换成*号
        List<RedPacketPageVO> redPacketPageVOS = page.getRecords();
        if (!CollectionUtils.isEmpty(redPacketPageVOS)){
            for (RedPacketPageVO redPacketPageVO : redPacketPageVOS) {
                redPacketPageVO.setNickname(strTox(redPacketPageVO.getNickname()));
            }
        }

        redPacketVO.setRedPacketPage(page);
        // 设置已被领取的总数
        redPacketVO.setReceivedCount(page.getTotal());
        // 设置今天派送的红包总数
        redPacketVO.setCount(redPacketPoolMapper.findCountByNowDate(nowStartDate,nowEndDate));

//        // 查询红包是否已经被抢完
//        RedPacketPool redPacket = redPacketPoolMapper.findOneByNowDate(nowStartDate, nowEndDate);
        // 红包为null说明已经抢完，则查询第一个抢的时间和最后抢的时间然后计算耗时
        if (!redPacketPoolMapper.existByNowDate(nowStartDate,nowEndDate)){
            Date startTime = redPacketPoolMapper.findDateByUpdatetime(nowStartDate,nowEndDate,"ASC");
            Date endTime = redPacketPoolMapper.findDateByUpdatetime(nowStartDate,nowEndDate,"DESC");
            if (startTime != null && endTime != null){
                redPacketVO.setTimeConsuming(TimeUtil.calculateMinute(startTime,endTime));
            }else {
                redPacketVO.setTimeConsuming(0L);
            }

        }

        // 用户抢到的金额
        Double userRedPacketMoney = redPacketPoolMapper.findRedPacketMoneyByUserId(nowStartDate, nowEndDate, userId);
        redPacketVO.setUserRedPacketMoney(userRedPacketMoney != null ? userRedPacketMoney : 0d);

        return redPacketVO;
    }

    /**
     * 除了第一个字，其余全部替换成*
     * @param text 待替换的文本
     * @return
     */
    private String strTox(String text){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < text.length(); i++) {

            if (i == 0){
                sb.append(text.charAt(i));
            }else {
                sb.append("*");
            }
        }

        return sb.toString();
    }

    /**
     * 红包概况
     * @return
     */
    @Override
    public RedPacketExistVO remainRedPacket() {
        String userId = tokenUtil.getUserId();
        RedPacketExistVO result = new RedPacketExistVO();

        String nowStartDate = TimeUtil.getNowStartDate();
        String nowEndDate = TimeUtil.getNowEndDate();
        // 红包是否已抢完
        result.setRedPacketExist(redPacketPoolMapper.existByNowDate(nowStartDate,nowEndDate));
        // 用户是否已抢过今日的红包
        result.setUserTodayExist(redPacketPoolMapper.existReceivedByNowDateAndUserId(nowStartDate,nowEndDate,userId));

        return result;
    }

    /**
     * 规则文案
     * @return
     */
    @Override
    public SysConfigRegulationVO regulation() {
        String userId = tokenUtil.getUserId();

        SysConfig sysConfig = sysConfigService.getOne(new LambdaQueryWrapper<SysConfig>()
                .orderByDesc(SysConfig::getUpdateTime)
                .last(" limit 1"));

        SysConfigRegulationVO result = new SysConfigRegulationVO();

        // 查询用户是否有抢红包资格,1.21改为先查询是否放过烟花
//        InviteFireworksRecord inviteFireworksRecord = inviteFireworksRecordMapper.selectOne(new LambdaQueryWrapper<InviteFireworksRecord>()
//                .eq(InviteFireworksRecord::getNuserId, userId)
//                .eq(InviteFireworksRecord::getInviteNewPeople, true)
//                .eq(InviteFireworksRecord::getSetOffFireworks, true)
//                .eq(InviteFireworksRecord::getRedPacketReceived, false)
//                .last(" limit 1"));
//        // 有资格则两个条件都是true
//        if (inviteFireworksRecord != null){
//            result.setInviteNewUser(true);
//            result.setSetOffFireworks(true);
//        }
//        // 没资格则查询少了什么资格
//        else {
//            // 是否放过烟花
//            if (inviteFireworksRecordMapper.exists(new LambdaQueryWrapper<InviteFireworksRecord>()
//                    .eq(InviteFireworksRecord::getNuserId,userId)
//                    .eq(InviteFireworksRecord::getSetOffFireworks,true)
//                    .eq(InviteFireworksRecord::getRedPacketReceived,false)
//                    .last(" limit 1"))){
//                result.setSetOffFireworks(true);
//            }
//
//            // 是否邀请过新人
//            if (inviteFireworksRecordMapper.exists(new LambdaQueryWrapper<InviteFireworksRecord>()
//                    .eq(InviteFireworksRecord::getNuserId,userId)
//                    .eq(InviteFireworksRecord::getInviteNewPeople,true)
//                    .eq(InviteFireworksRecord::getRedPacketReceived,false)
//                    .last(" limit 1"))){
//                result.setInviteNewUser(true);
//            }
//
//        }

        if (inviteFireworksRecordMapper.exists(new LambdaQueryWrapper<InviteFireworksRecord>()
                .eq(InviteFireworksRecord::getNuserId, userId)
                .eq(InviteFireworksRecord::getSetOffFireworks, true)
                .eq(InviteFireworksRecord::getRedPacketReceived, false)
                .last(" limit 1"))) {
            result.setSetOffFireworks(true);
        }


        if (sysConfig == null){
            result.setNewUser(300);
            result.setMinMoney("0.1");
            result.setMaxMoney("0.88");
            result.setMaxNum("20100");
            result.setDiffNum("300");
            return result;
        }

        result.setNewUser(sysConfig.getNewUserNumber());
        result.setMaxMoney(String.valueOf(sysConfig.getRedOneMax()));
        result.setMinMoney(String.valueOf(sysConfig.getRedOneMin()));
        result.setMaxNum(String.valueOf(sysConfig.getRedEverydayMaxNum()));

        String nowStartDate = TimeUtil.getNowStartDate();
        String nowEndDate = TimeUtil.getNowEndDate();

        // 查询今日红包是否已达上限
        Long countByNowDate = redPacketPoolMapper.findCountByNowDate(nowStartDate, nowEndDate);
        if (countByNowDate >= Long.valueOf(sysConfig.getRedEverydayMaxNum())){
            result.setRedPacketMax(true);
        }
        // 没达上限则返回差多少人
        else {
            // 查询当天多少个新人燃放烟花
            List<InviteFireworksRecord> inviteFireworksRecords = inviteFireworksRecordMapper.findListByTimeAndFsoAndIsrp(nowStartDate, nowEndDate, sysConfig.getNewUserNumber());


            if (!CollectionUtils.isEmpty(inviteFireworksRecords)) {
                //数量大于新人配置数量则差的人数为0
                if (inviteFireworksRecords.size() > sysConfig.getNewUserNumber()) {
                    result.setDiffNum("0");
                } else {
                    int i = sysConfig.getNewUserNumber() - inviteFireworksRecords.size();
                    result.setDiffNum(String.valueOf(i));
                }

            }
            // 如果数量<=0，那么差的数量就是新人数量的配置数
            else {
                result.setDiffNum(String.valueOf(sysConfig.getNewUserNumber()));
            }
        }


        return result;
    }

    /**
     * 开红包
     * @param form
     * @return
     */
    @Override
    public boolean openRedPacket(OpenRedPacketForm form) {
        String userId = tokenUtil.getUserId();

        Nuser nuser = nuserService.getById(userId);
        if (nuser == null){
            throw new MyErrorException(ErrorConstants.USER_IS_NULL);
        }


        // 先验证签名
        String verifiSign = DigestUtils.md5DigestAsHex((nuser.getId() + form.getRedPacketId() + CommonConstants.appKey).getBytes());
        if (!verifiSign.equals(form.getSign())){
            throw new MyErrorException(ErrorConstants.SYS_SIGN_ERROR);
        }

        // 提取uopenid
        String uOpenid = nuser.getUOpenid();
        if (uOpenid == null){
            uOpenid = form.getUOpenid();
        }


        // 查询红包是否存在
        //RedPacketPool redPacketPool = redPacketPoolMapper.selectById(form.getRedPacketId());
        RedPacketPool redPacketPool = redPacketPoolMapper.selectOne(new LambdaQueryWrapper<RedPacketPool>()
                .eq(RedPacketPool::getId, form.getRedPacketId())
                .eq(RedPacketPool::getReceiveNuserId, nuser.getId())
                .eq(RedPacketPool::getAlreadyReceived, true));


        if (redPacketPool == null){
            throw new MyErrorException(ErrorConstants.SYS_SIGN_ERROR);
        }


        // 先更新红包订单号
        String orderid = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + RandomUtil.randomNumbers(4);
        if (redPacketPoolMapper.update(null, new LambdaUpdateWrapper<RedPacketPool>()
                .eq(RedPacketPool::getId, redPacketPool.getId())
                .set(RedPacketPool::getWxOrderNumber, orderid)
        ) <= 0){
            return false;
        }

        // 给用户转账
        boolean sendRedPacket = yaoSendRedPacket(redPacketPool, uOpenid, orderid);

        // uopenid为空则更新
        if (StringUtils.isEmpty(nuser.getUOpenid())){
            nuserService.update(new LambdaUpdateWrapper<Nuser>()
                    .eq(Nuser::getId,nuser.getId())
                    .set(Nuser::getUOpenid,form.getUOpenid()));
        }


        return sendRedPacket;
    }

//    /**
//     * 测试接口
//     */
//    @Override
//    public void test() {
//
////        String nowStartDate = TimeUtil.getNowStartDate();
////        String nowEndDate = TimeUtil.getNowEndDate();
//
////        RedPacketPool redPacket = null;
////        // 先查询是否还有大红包
////        redPacket = redPacketPoolMapper.findOneMaxByNowDate(nowStartDate, nowEndDate, 0.5);
////
////        // 没有则判断当天是否还有红包
////        if (redPacket == null){
////            redPacket = redPacketPoolMapper.findOneByNowDate(nowStartDate, nowEndDate);
////        }
////
////        System.out.println(redPacket);
//
////        SysConfig sysConfig = sysConfigService.getOne(new LambdaQueryWrapper<SysConfig>()
////                .orderByDesc(SysConfig::getUpdateTime)
////                .last(" limit 1"));
////        if (sysConfig == null){
////            return;
////        }
////
////
//
////
////        if (!redPacketPoolMapper.exists(new LambdaQueryWrapper<RedPacketPool>()
////                .between(RedPacketPool::getCreateTime,nowStartDate,nowEndDate)
////                .ge(RedPacketPool::getRedPacketMoney,sysConfig.getRedOneRandomMin()))){
////
////            List<RedPacketPool> redPacketRandoms = RedPacketUtil.assRedPacketRandom(sysConfig.getRedOneRandomTotalMoney(), sysConfig.getRedOneRandomNum(),
////                    String.valueOf(sysConfig.getRedOneRandomMin()), String.valueOf(sysConfig.getRedOneRandomMax()));
////            System.out.println(redPacketRandoms);
////
////        }
//
//        // 发6000个红包
//        List<RedPacketPool> redPacketPools = RedPacketUtil.assRedPacketFixed(6000, 0, 0.1, 0.88);
//        System.out.println(redPacketPools.size());
//        System.out.println(redPacketPools.get(0));
//        System.out.println(redPacketPools.get(1));
//        System.out.println(redPacketPoolService.saveBatch(redPacketPools));
//
//
//    }

    /**
     * 摇摇啦第三方平台发红包
     * @param redPacketPool 红包
     * @param uOpenid 第三方openid
     * @param orderid 自定义订单号
     * @return
     */
    private boolean yaoSendRedPacket(RedPacketPool redPacketPool,String uOpenid,String orderid){

        String reqtick = String.valueOf(System.currentTimeMillis()).substring(0,10);

        String uid = CommonConstants.YAO_UID;
        Integer type = 1;
        String money = String.valueOf(redPacketPool.getRedPacketMoney() * 100).replace(".0","");
        String apikey = CommonConstants.YAO_APPKEY;

        // 签名
        String sign = DigestUtils.md5DigestAsHex((uid + type + orderid + money + reqtick + uOpenid + apikey).getBytes());
        // 发送红包参数
        YaoYaoLaRedPacket yaoLaRedPacket = YaoYaoLaRedPacket.builder()
                .uid(uid)
                .type(type)
                .orderid(orderid)
                .money(money)
                .reqtick(reqtick)
                .openid(uOpenid)
                .sign(sign)
                .title(CommonConstants.YAO_REDPACKET_TITLE)
                .sendname(CommonConstants.YAO_REDPACKET_SENDNAME)
                .wishing(CommonConstants.YAO_REDPACKET_WISHING).build();

        // 组装参数
        String url = assParam(yaoLaRedPacket);
        JSONObject data = restTemplateUtil.getData(url);
        System.out.println("========data:" + data);
        if (ObjectUtil.isNull(data)) {
            return false;
            //throw new MyErrorException("转账失败");
        }

        // 异步发送日志
        sendYaoLog(data,orderid);

        if (data.containsKey("errcode") && !data.getString("errcode").equals("0")) {
            if (data.containsKey("errmsg")) {
                return false;
            }
        }


        return true;

    }


    private static String assParam(YaoYaoLaRedPacket yaoLaRedPacket){
        return  StrUtil.format(CommonConstants.YAO_REDPACKET_URL,yaoLaRedPacket.getUid(),yaoLaRedPacket.getType(),yaoLaRedPacket.getOrderid(),
                yaoLaRedPacket.getMoney(),yaoLaRedPacket.getReqtick(),yaoLaRedPacket.getOpenid(),yaoLaRedPacket.getSign(),yaoLaRedPacket.getTitle(),
                yaoLaRedPacket.getSendname(),yaoLaRedPacket.getWishing());
    }

    /**
     * 异步发送摇摇啦日志
     */
    @Async
    public void sendYaoLog(JSONObject data,String orderNumber){

        String remark = "发放正常";

        if (data.containsKey("errcode") && !data.getString("errcode").equals("0")) {
            if (data.containsKey("errmsg")) {
                // 保存到日志表
                remark = "接口调用异常";
            }
        }

        yaoExceptionsService.yaoExceptionDispose(data,remark,orderNumber);
    }

}
